﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace TCPClient
{
    public partial class ClientForm : Form
    {
        public Socket _newClient;
        public bool _isConnect;
        public String STRING_DISCONNECT_MESSAGE = "--I am offline.--";
        public String STRING_CHANGE_NAME = "change your user name,";
        public String STRING_HANDUP_MESSAGE = "handup.";
        public bool _isKeyChanged = false;
        public DiffieHellman _diffieHellmanclient;
        public Byte[] _commonSecret;
        public String _clientName;
        public int _clientNameLegnth = 0;
        private Byte[] _msgBuffer = new Byte[65535];                  //存放消息数据

        public delegate void IncomeInvoke(string message);

        public ClientForm() {
            Form.CheckForIllegalCrossThreadCalls = false;
            InitializeComponent();
            disConnectButton.Enabled = false;
        }

        public void Connect() {
<<<<<<< .mine
            //Console.WriteLine("Connect");
=======
            // Console.WriteLine("Connect"); //test debug
>>>>>>> .r31

            try
            {
                _diffieHellmanclient = new DiffieHellman(64).GenerateRequest();
                Console.WriteLine("DiffieHellman : " + _diffieHellmanclient.ToString());
                _newClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                String serverIp = serverIpTextBox.Text.Trim();
                int serverPort = Convert.ToInt32(serverPortTextPort.Text.Trim());
                IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse(serverIp), serverPort);
                _clientName = clientNameTextBox.Text.ToString();

                _newClient.Connect(serverEndPoint);

                String messageToSend = _diffieHellmanclient.ToString() + "," + _clientName;
                int messageLength = messageToSend.Length;
                Byte[] data = new Byte[messageLength];
                data = Encoding.UTF8.GetBytes(messageToSend);
                _newClient.Send(data);

                data = new byte[65535];
                int REnd = _newClient.Receive(data, 0, data.Length, SocketFlags.None);
<<<<<<< .mine
                //Console.WriteLine(REnd);
=======
                //Console.WriteLine(REnd);  //test debug
>>>>>>> .r31
                _diffieHellmanclient.HandleResponse(Encoding.UTF8.GetString(data, 0, REnd).ToString());
                _commonSecret = _diffieHellmanclient.Key;
                Console.WriteLine("Shared-Key : " + Convert.ToBase64String(_commonSecret));

                REnd = _newClient.Receive(data, 0, data.Length, SocketFlags.None);
                String receiveString = Encoding.UTF8.GetString(data, 0, REnd);
<<<<<<< .mine
                //Console.WriteLine(receiveString.Length);
=======
                //Console.WriteLine(receiveString.Length);  //test debug
>>>>>>> .r31
                Byte[] encryptedData = System.Text.Encoding.UTF8.GetBytes(receiveString);
                Byte[] decryptedData = DESFactory.DecryptDES(encryptedData, _commonSecret);//解密
                String realMsgReceive = Encoding.UTF8.GetString(decryptedData);

                if (realMsgReceive.Contains(STRING_CHANGE_NAME))
                {
                    MessageBox.Show(realMsgReceive.ToString());
                    DisConnect();
                }

                SendMessage("-- I am now online.--");

                _isKeyChanged = true;
                _isConnect = true;
                SendMsgButton.Enabled = _isConnect;
                connectButton.Enabled = false;
                disConnectButton.Enabled = true;

                _newClient.BeginReceive(_msgBuffer,0, _msgBuffer.Length, SocketFlags.None,
                                        new AsyncCallback(ReciveCallBack),
                                        _newClient);

            }
            catch (SocketException e)
            {
                MessageBox.Show("Failed, " + e.Message);
                DisConnect();
                return;
            }

<<<<<<< .mine
            //Console.WriteLine("Connect end");
=======
            //Console.WriteLine("Connect end");  //test debug
>>>>>>> .r31
        }

        private void ReciveCallBack(IAsyncResult AR)
        {
            Byte[] encryptedData;//待解密的data
            Byte[] decryptedData;
            String realMsgReceive;
            Socket RSocket = (Socket)AR.AsyncState;

            if (_isConnect)
            {
                try
                {
                    
                    int REnd = RSocket.EndReceive(AR);
                    String receiveString = Encoding.UTF8.GetString(_msgBuffer, 0, REnd);
<<<<<<< .mine
                    //Console.WriteLine(receiveString.Length);
=======
                    //Console.WriteLine(receiveString.Length);   //test debug
>>>>>>> .r31
                    encryptedData = System.Text.Encoding.UTF8.GetBytes(receiveString);
                    decryptedData = DESFactory.DecryptDES(encryptedData, _commonSecret);//解密
                    realMsgReceive = Encoding.UTF8.GetString(decryptedData);

                    _clientNameLegnth = (clientNameTextBox.Text.ToString() + ",").ToString().Length;
                    ShowMsg(realMsgReceive);
                    RSocket.BeginReceive(_msgBuffer, 0, _msgBuffer.Length, 0, new AsyncCallback(ReciveCallBack), RSocket);
                    
                    if (realMsgReceive.Contains(STRING_HANDUP_MESSAGE))
                    {
                        DisConnect();
                        //Console.WriteLine("server handup");   //test debug
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                    //RSocket.EndReceive(AR);
                    DisConnect();
                }
            }
            else
            {
                 RSocket.EndReceive(AR);
                 //Console.WriteLine("end receive");  //test debug
            }
        }

        public void ShowMsg(string msg) {
            if (receiveMsgRichTextBox.InvokeRequired)
            {
                IncomeInvoke _myinvoke = new IncomeInvoke(ShowMsg);
                receiveMsgRichTextBox.Invoke(_myinvoke, new object[] { msg });
            } else
            {
                receiveMsgRichTextBox.AppendText(msg + "\r\n");
                receiveMsgRichTextBox.ScrollToCaret();
                receiveMsgRichTextBox.Refresh();
            }
        }

        private void SendMsg_Click(object sender, EventArgs e) {
            String messageToSend = messageToSendTextBox.Text.ToString();
            SendMessage(messageToSend);
            messageToSendTextBox.Text = "";
        }

        private void SendMessage(String messageToSend) {
            Byte[] data;
            Byte[] encryedData;
            Byte[] nameData = new Byte[_clientNameLegnth + 1];
            nameData = Encoding.UTF8.GetBytes(_clientName + ",");

            try
            {
                int messageLength = messageToSend.Length;
                data = new Byte[messageLength];
                data = Encoding.UTF8.GetBytes(messageToSend);

                encryedData = DESFactory.EncryptDES(data, _commonSecret);//加密

                var list = new List<Byte>();
                list.AddRange(nameData);
                list.AddRange(encryedData);
                data = list.ToArray();

                Console.WriteLine("Send data : " + Encoding.UTF8.GetString(data));
                _newClient.Send(data);
            }
            catch (Exception e)
            {
                _newClient.Close();
                _isConnect = false;
                connectButton.Enabled = true;
                disConnectButton.Enabled = false;
                SendMsgButton.Enabled = _isConnect;
                MessageBox.Show("Failed, " + e.Message);
                return;
            }
        }

        private void Connect_Click(object sender, EventArgs e) {
            if (clientNameTextBox.Text.ToString() == "")
            {
                MessageBox.Show("Please enter your user name fisrt.");
            } else
            {
                Connect();
                clientNameTextBox.Enabled = false;
            }
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e) {
            DisConnect();
        }

        private void disConnectButton_Click(object sender, EventArgs e) {
            SendMessage(STRING_DISCONNECT_MESSAGE);
            DisConnect();
        }

        private void DisConnect()
        {
            if (_isConnect)
            {
                _isConnect = false;
                _isKeyChanged = false;
                connectButton.Enabled = true;
                disConnectButton.Enabled = false;
                clientNameTextBox.Enabled = true;
                SendMsgButton.Enabled = _isConnect;
                _newClient.Close();
            }
        }
    }
}
